home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint108s.zoo / proc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-27  |  13.9 KB  |  660 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* routines for handling processes */
  8.  
  9. #include "mint.h"
  10. #include "xbra.h"
  11.  
  12. static void do_wakeup_things P_((void));
  13.  
  14. extern short proc_clock;
  15.  
  16. /* global process variables */
  17. PROC *proclist;            /* list of all active processes */
  18. PROC *curproc;            /* current process        */
  19. PROC *rootproc;            /* pid 0 -- MiNT itself        */
  20. PROC *sys_q[NUM_QUEUES];
  21.  
  22. short time_slice = 2;        /* default; actual value comes from mint.cnf */
  23.  
  24. #if 0
  25. #define TIME_SLICE    2    /* number of 20ms ticks before process is
  26.                    pre-empted */
  27. #else
  28. #define TIME_SLICE time_slice
  29. #endif
  30.  
  31. /* macro for calculating number of missed time slices, based on a
  32.  * process' priority
  33.  */
  34. #define SLICES(pri)    (((pri) >= 0) ? 0 : -(pri))
  35.  
  36. extern FILESYS bios_filesys;
  37.  
  38. /*
  39.  * get a new process struct
  40.  */
  41.  
  42. PROC *
  43. new_proc()
  44. {
  45.     PROC *p;
  46.     void *pt;
  47.  
  48.     pt = kmalloc(page_table_size + 16);
  49.     if (!pt) return 0;
  50.  
  51.     p = (PROC *)kmalloc(SIZEOF(PROC));
  52.     if (!p) {
  53.         kfree(pt);
  54.         return 0;
  55.     }
  56. /* page tables must be on 16 byte boundaries, so we
  57.  * round off by 16 for that; however, we will want to
  58.  * kfree that memory at some point, so we squirrel
  59.  * away the original address for later use
  60.  */
  61.     p->page_table = ROUND16(pt);
  62.     p->pt_mem = pt;
  63.     return p;
  64. }
  65.  
  66. /*
  67.  * dispose of an old proc
  68.  */
  69.  
  70. void
  71. dispose_proc(p)
  72.     PROC *p;
  73. {
  74. TRACELOW(("dispose_proc"));
  75.     kfree(p->pt_mem);
  76.     kfree(p);
  77. }
  78.  
  79. /*
  80.  * create a new process that is (practically) a duplicate of the
  81.  * current one
  82.  */
  83.  
  84. PROC *
  85. fork_proc()
  86. {
  87.     PROC *p;
  88.     int i;
  89.     FILEPTR *f;
  90.     long_desc *pthold;
  91.     void *ptmemhold;
  92.  
  93.     if ((p = new_proc()) == 0) {
  94. nomem:
  95.         DEBUG(("fork_proc: insufficient memory"));
  96.         mint_errno = ENSMEM; return 0;
  97.     }
  98.  
  99. /* child shares most things with parent, but hold on to page table ptr */
  100.     pthold = p->page_table;
  101.     ptmemhold = p->pt_mem;
  102.     *p = *curproc;
  103.     p->page_table = pthold;
  104.     p->pt_mem = ptmemhold;
  105.  
  106. /* these things are not inherited */
  107.     p->ppid = curproc->pid;
  108.     p->pid = newpid();
  109.     p->sigpending = 0;
  110.     p->sysstack = (long)(p->stack + STKSIZE - 12);
  111.     p->ctxt[CURRENT].ssp = p->sysstack;
  112.     p->ctxt[SYSCALL].ssp = (long)(p->stack + ISTKSIZE);
  113.     p->alarmtim = 0;
  114.     p->curpri = p->pri;
  115.     p->slices = SLICES(p->pri);
  116.     p->starttime = timestamp;
  117.     p->startdate = datestamp;
  118.  
  119.     ((long *)p->sysstack)[1] = FRAME_MAGIC;
  120.     ((long *)p->sysstack)[2] = 0;
  121.     ((long *)p->sysstack)[3] = 0;
  122.  
  123.     p->usrtime = p->systime = p->chldstime = p->chldutime = 0;
  124.  
  125. /* copy open handles */
  126.     for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  127.         if ((f = p->handle[i]) != 0) {
  128.             if (f->flags & O_NOINHERIT)
  129.         /* oops, we didn't really want to copy this handle */
  130.                 p->handle[i] = 0;
  131.             else
  132.                 f->links++;
  133.         }
  134.     }
  135.  
  136. /* copy root and current directories */
  137.     for (i = 0; i < NUM_DRIVES; i++) {
  138.         dup_cookie(&p->root[i], &curproc->root[i]);
  139.         dup_cookie(&p->curdir[i], &curproc->curdir[i]);
  140.     }
  141.  
  142. /* jr: copy ploadinfo */
  143.     strcpy (p->cmdlin, curproc->cmdlin);
  144.     strcpy (p->fname, curproc->fname);
  145.  
  146. /* clear directory search info */
  147.     zero((char *)p->srchdta, NUM_SEARCH * SIZEOF(DTABUF *));
  148.     zero((char *)p->srchdir, SIZEOF(p->srchdir));
  149.     p->searches = 0;
  150.  
  151. /* copy memory */
  152.     p->mem = (MEMREGION **) kmalloc(p->num_reg * SIZEOF(MEMREGION *));
  153.     if (!p->mem) {
  154.         dispose_proc(p);
  155.         goto nomem;
  156.     }
  157.     p->addr = (virtaddr *)kmalloc(p->num_reg * SIZEOF(virtaddr));
  158.     if (!p->addr) {
  159.         kfree(p->mem);
  160.         dispose_proc(p);
  161.         goto nomem;
  162.     }
  163.  
  164.     for (i = 0; i < curproc->num_reg; i++) {
  165.         p->mem[i] = curproc->mem[i];
  166.         if (p->mem[i] != 0)
  167.             p->mem[i]->links++;
  168.         p->addr[i] = curproc->addr[i];
  169.     }
  170.  
  171. /* now that memory ownership is copied, fill in page table */
  172.     init_page_table(p);
  173.  
  174. /* child isn't traced */
  175.     p->ptracer = 0;
  176.     p->ptraceflags = 0;
  177.  
  178.     p->starttime = Tgettime();
  179.     p->startdate = Tgetdate();
  180.  
  181.     p->q_next = 0;
  182.     p->wait_q = 0;
  183.     p->gl_next = proclist;
  184.     proclist = p;            /* hook into the process list */
  185.     return p;
  186. }
  187.  
  188. /*
  189.  * initialize the process table
  190.  */
  191.  
  192. void
  193. init_proc()
  194. {
  195.     int i;
  196.     FILESYS *fs;
  197.     fcookie dir;
  198.     long_desc *pthold;
  199.     void *ptmemhold;
  200.  
  201.     rootproc = curproc = new_proc();
  202.     assert(curproc);
  203.  
  204.     pthold = curproc->page_table;
  205.     ptmemhold = curproc->pt_mem;
  206.     zero((char *)curproc, (long)sizeof(PROC));
  207.     curproc->page_table = pthold;
  208.     curproc->pt_mem = ptmemhold;
  209.  
  210.     curproc->ppid = -1;        /* no parent */
  211.     curproc->domain = DOM_TOS;    /* TOS domain */
  212.     curproc->sysstack = (long) (curproc->stack+STKSIZE-12);
  213.     curproc->magic = CTXT_MAGIC;
  214.     curproc->memflags = F_PROT_S;    /* default prot mode: super-only */
  215.     ((long *)curproc->sysstack)[1] = FRAME_MAGIC;
  216.     ((long *)curproc->sysstack)[2] = 0;
  217.     ((long *)curproc->sysstack)[3] = 0;
  218.  
  219. /* NOTE: in main.c this could be changed, later */
  220.     curproc->base = _base;
  221.  
  222.     strcpy(curproc->name, "MiNT");
  223.  
  224. /* get some memory */
  225.     curproc->mem = (MEMREGION **)kmalloc(NUM_REGIONS*SIZEOF(MEMREGION *));
  226.     curproc->addr = (virtaddr *)kmalloc(NUM_REGIONS*SIZEOF(virtaddr));
  227.     assert(curproc->mem && curproc->addr);
  228.  
  229. /* make sure it's filled with zeros */
  230.     zero((char *)curproc->addr, NUM_REGIONS * SIZEOF(virtaddr));
  231.     zero((char *)curproc->mem, NUM_REGIONS * SIZEOF(MEMREGION *));
  232.     curproc->num_reg = NUM_REGIONS;
  233.  
  234. /* get root and current directories for all drives */
  235.     for (i = 0; i < NUM_DRIVES; i++) {
  236.         if ((fs = drives[i]) != 0 && (*fs->root)(i, &dir) == E_OK) {
  237.                 dup_cookie(&curproc->curdir[i], &dir);
  238.                 curproc->root[i] = dir;
  239.         } else {
  240.             curproc->root[i].fs = curproc->curdir[i].fs = 0;
  241.             curproc->root[i].dev = curproc->curdir[i].dev = i;
  242.         }
  243.     }
  244.  
  245.     init_page_table(curproc);
  246.  
  247. /* Set the correct drive. The current directory we
  248.  * set later, after all file systems have been loaded.
  249.  */
  250.  
  251.     curproc->curdrv = Dgetdrv();
  252.     proclist = curproc;
  253.  
  254.     curproc->umask = 0;
  255.  
  256. /*
  257.  * some more protection against job control; unless these signals are
  258.  * re-activated by a shell that knows about job control, they'll have
  259.  * no effect
  260.  */
  261.     curproc->sighandle[SIGTTIN] = curproc->sighandle[SIGTTOU] =
  262.         curproc->sighandle[SIGTSTP] = SIG_IGN;
  263.  
  264. /* set up some more per-process variables */
  265.     curproc->starttime = Tgettime();
  266.     curproc->startdate = Tgetdate();
  267.     if (has_bconmap)
  268.         curproc->bconmap = curbconmap;
  269.     else
  270.         curproc->bconmap = 1;
  271.  
  272.     curproc->logbase = (void *)Logbase();
  273.     curproc->criticerr = *((long ARGS_ON_STACK (**) P_((long)))0x404L);
  274. }
  275.  
  276. /*
  277.  * reset all process priorities to their base level
  278.  * called once per second, so that cpu hogs can get _some_ time
  279.  * slices :-).
  280.  */
  281.  
  282. void
  283. reset_priorities()
  284. {
  285.     PROC *p;
  286.  
  287.     for (p = proclist; p; p = p->gl_next) {
  288.         p->curpri = p->pri;
  289.         p->slices = SLICES(p->curpri);
  290.     }
  291. }
  292.  
  293. /*
  294.  * more priority code stuff:
  295.  * run_next(p, slices): schedule process "p" to run next, with "slices"
  296.  *       initial time slices; "p" does not actually start running until
  297.  *       the next context switch
  298.  * fresh_slices(slices): give the current process "slices" more slices in
  299.  *       which to run
  300.  */
  301.  
  302. void
  303. run_next(p, slices)
  304.     PROC *p;
  305.     int slices;    /* BUG: currently ignored */
  306. {
  307.     UNUSED(slices);
  308.  
  309.     p->slices = 0;
  310.     p->curpri = MAX_NICE;
  311.     p->wait_q = READY_Q;
  312.     p->q_next = sys_q[READY_Q];
  313.     sys_q[READY_Q] = p;
  314. }
  315.  
  316. void
  317. fresh_slices(slices)
  318.     int slices;
  319. {
  320.     curproc->slices = 0;
  321.     curproc->curpri = MAX_NICE+1;
  322.     proc_clock = slices;
  323. }
  324.  
  325. /*
  326.  * add a process to a wait (or ready) queue.
  327.  *
  328.  * processes go onto a queue in first in-first out order
  329.  */
  330.  
  331. void
  332. add_q(que, proc)
  333.     int que;
  334.     PROC *proc;
  335. {
  336.     PROC *q, **lastq;
  337.  
  338. /* "proc" should not already be on a list */
  339.     assert(proc->wait_q == 0);
  340.     assert(proc->q_next == 0);
  341.  
  342.     lastq = &sys_q[que];
  343.     q = *lastq;
  344.     while(q) {
  345.         lastq = &q->q_next;
  346.         q = *lastq;
  347.     }
  348.     *lastq = proc;
  349.     proc->wait_q = que;
  350.     if (que != READY_Q) {
  351.         proc->curpri = proc->pri;    /* reward the process */
  352.         proc->slices = SLICES(proc->curpri);
  353.     }
  354. }
  355.  
  356. /*
  357.  * remove a process from a queue
  358.  */
  359.  
  360. void
  361. rm_q(que, proc)
  362.     int que;
  363.     PROC *proc;
  364. {
  365.     PROC *q;
  366.     PROC *old = 0;
  367.  
  368.     assert(proc->wait_q == que);
  369.  
  370.     q = sys_q[que];
  371.     while (q && q != proc) {
  372.         old = q;
  373.         q = q->q_next;
  374.     }
  375.     if (q == 0)
  376.         FATAL("rm_q: unable to remove process from queue");
  377.  
  378.     if (old)
  379.         old->q_next = proc->q_next;
  380.     else
  381.         sys_q[que] = proc->q_next;
  382.  
  383.     proc->wait_q = 0;
  384.     proc->q_next = 0;
  385. }
  386.  
  387. /*
  388.  * preempt(): called by the vbl routine and/or the trap handlers when
  389.  * they detect that a process has exceeded its time slice and hasn't
  390.  * yielded gracefully. For now, it just does sleep(READY_Q); later,
  391.  * we might want to keep track of statistics or something.
  392.  */
  393.  
  394. void ARGS_ON_STACK
  395. preempt()
  396. {
  397.     extern short bconbsiz;    /* in bios.c */
  398.  
  399.     if (bconbsiz)
  400.         (void)bflush();
  401.     else {
  402.         /* punish the pre-empted process */
  403.         if (curproc->curpri >= MIN_NICE)
  404.             curproc->curpri -= 1;
  405.     }
  406.     sleep(READY_Q, curproc->wait_cond);
  407. }
  408.  
  409. /*
  410.  * sleep(que, cond): put the current process on the given queue, then switch
  411.  * contexts. Before a new process runs, give it a fresh time slice. "cond"
  412.  * is the condition for which the process is waiting, and is placed in
  413.  * curproc->wait_cond
  414.  */
  415.  
  416. static void
  417. do_wakeup_things()
  418. {
  419. /*
  420.  * check for stack underflow, just in case
  421.  */
  422.     auto int foo;
  423.     PROC *p;
  424.  
  425.     p = curproc;
  426.  
  427.     if ( p->pid != 0 &&
  428.          ((long)&foo) < (long)p->stack + ISTKSIZE + 512 ) {
  429.         ALERT("stack underflow");
  430.         handle_sig(SIGBUS);
  431.     }
  432.  
  433. /* see if process' time limit has been exceeded */
  434.  
  435.     if (p->maxcpu) {
  436.         if (p->maxcpu <= p->systime + p->usrtime) {
  437.             DEBUG(("cpu limit exceeded"));
  438.             raise(SIGXCPU);
  439.         }
  440.     }
  441.  
  442. /*
  443.  * check for alarms and similar time out stuff (see timeout.c)
  444.  */
  445.  
  446.     checkalarms();
  447.     if (p->sigpending)
  448.         check_sigs();        /* check for signals */
  449.  
  450.     proc_clock = TIME_SLICE;    /* get a fresh time slice */
  451.     p->slices = SLICES(p->curpri);
  452. }
  453.  
  454. void ARGS_ON_STACK 
  455. sleep(que, cond)
  456.     int que;
  457.     long cond;
  458. {
  459.     PROC *p;
  460.     short sr;
  461.     extern short kintr;    /* in bios.c */
  462. #ifndef MULTITOS
  463. #ifdef FASTTEXT
  464.     extern int hardscroll;    /* in fasttext.c */
  465. #endif
  466. #endif
  467.  
  468. /*
  469.  * if there have been keyboard interrupts since our last sleep, check for
  470.  * special keys like CTRL-ALT-Fx
  471.  */
  472.  
  473.     if (kintr) {
  474.         (void)checkkeys();
  475.         kintr = 0;
  476.     }
  477.  
  478.     if (que == READY_Q && !sys_q[READY_Q]) {
  479. /* we're just going to wake up again right away! */
  480.         do_wakeup_things();
  481.         return;
  482.     }
  483.  
  484.     sr = spl7();
  485.  
  486.     add_q(que, curproc);
  487.     curproc->wait_cond = cond;
  488.  
  489.     if (!sys_q[READY_Q]) {
  490. /* hmm, no-one is ready to run. might be a deadlock, might not.
  491.  * first, try waking up any napping processes; if that doesn't work,
  492.  * run the root process, just so we have someone to charge time
  493.  * to.
  494.  */
  495.         wake(SELECT_Q, (long)nap);
  496.         if (!sys_q[READY_Q]) {
  497.             p = rootproc;        /* pid 0 */
  498.             rm_q(p->wait_q, p);
  499.             add_q(READY_Q, p);
  500.         }
  501.     }
  502.  
  503. /*
  504.  * Walk through the ready list, to find what process should run next.
  505.  * Lower priority processes don't get to run every time through this
  506.  * loop; if "p->slices" is positive, it's the number of times that they
  507.  * will have to miss a turn before getting to run again
  508.  */
  509.  
  510. /*
  511.  * Loop structure:
  512.  *    while (we haven't picked anybody) {
  513.  *        for (each process) {
  514.  *            if (sleeping off a penalty) {
  515.  *                decrement penalty counter
  516.  *            }
  517.  *            else {
  518.  *                pick this one and break out of both loops
  519.  *            }
  520.  *        }
  521.  *    }
  522.  */
  523.     p = 0;
  524.  
  525.     while (!p) {
  526.         for (p = sys_q[READY_Q]; p; p = p->q_next) {
  527.             if (p->slices > 0)
  528.                 p->slices--;
  529.             else
  530.                 break;
  531.         }
  532.     }
  533.  
  534.     /* p is our victim */
  535.  
  536.     rm_q(READY_Q, p);
  537.  
  538.     spl(sr);
  539.  
  540.     if (save_context(&(curproc->ctxt[CURRENT]))) {
  541. /*
  542.  * restore per-process variables here
  543.  */
  544. #ifndef MULTITOS
  545. #ifdef FASTTEXT
  546.         if (!hardscroll)
  547. #endif
  548.             *((void **)0x44eL) = curproc->logbase;
  549. #endif
  550.         do_wakeup_things();
  551.         return;
  552.     }
  553. /*
  554.  * save per-process variables here
  555.  */
  556. #ifndef MULTITOS
  557. #ifdef FASTTEXT
  558.     if (!hardscroll)
  559. #endif
  560.         curproc->logbase = *((void **)0x44eL);
  561. #endif
  562.     curproc->ctxt[CURRENT].regs[0] = 1;
  563.     curproc = p;
  564.     proc_clock = TIME_SLICE;    /* fresh time */
  565.     if ((p->ctxt[CURRENT].sr & 0x2000) == 0) {    /* user mode? */
  566.         leave_kernel();
  567.     }
  568.     assert(p->magic == CTXT_MAGIC);
  569.     change_context(&(p->ctxt[CURRENT]));
  570. }
  571.  
  572. /*
  573.  * wake(que, cond): wake up all processes on the given queue that are waiting
  574.  * for the indicated condition
  575.  */
  576.  
  577. void ARGS_ON_STACK 
  578. wake(que, cond)
  579.     int que;
  580.     long cond;
  581. {
  582.     PROC *p;
  583.  
  584.     if (que == READY_Q) {
  585.         ALERT("wake: why wake up ready processes??");
  586.         return;
  587.     }
  588. top:
  589.     for(p = sys_q[que]; p; p = p->q_next) {
  590.         if (p->wait_cond == cond) {
  591.             short s = spl7();
  592.             rm_q(que, p);
  593.             add_q(READY_Q, p);
  594.             spl(s);
  595.             goto top;
  596.         }
  597.     }
  598. }
  599.  
  600. /*
  601.  * wakeselect(p): wake process p from a select() system call
  602.  * may be called by an interrupt handler or whatever
  603.  */
  604.  
  605. void ARGS_ON_STACK 
  606. wakeselect(param)
  607.     long param;
  608. {
  609.     PROC *p = (PROC *)param;
  610.     short s;
  611.  
  612.     s = spl7();    /* block interrupts */
  613.     if(p->wait_cond == (long)wakeselect) {
  614.         p->wait_cond = 0;
  615.     }
  616.     if (p->wait_q == SELECT_Q) {
  617.         rm_q(SELECT_Q, p);
  618.         add_q(READY_Q, p);
  619.     }
  620.     spl(s);
  621. }
  622.  
  623. /*
  624.  * dump out information about processes
  625.  */
  626.  
  627. /*
  628.  * kludge alert! In order to get the right pid printed by FORCE, we use
  629.  * curproc as the loop variable.
  630.  *
  631.  * I have changed this function so it is more useful to a user, less to
  632.  * somebody debugging MiNT.  I haven't had any stack problems in MiNT
  633.  * at all, so I consider all that stack info wasted space.  -- AKP
  634.  */
  635.  
  636. #ifdef DEBUG_INFO
  637. static const char *qstring[] = {
  638.     "run", "ready", "wait", "iowait", "zombie", "tsr", "stop", "select"
  639. };
  640.  
  641. /* UNSAFE macro for qname, evaluates x 1, 2, or 3 times */
  642. #define qname(x) ((x >= 0 && x < NUM_QUEUES) ? qstring[x] : "unkn")
  643. #endif
  644.  
  645. void
  646. DUMPPROC()
  647. {
  648. #ifdef DEBUG_INFO
  649.     PROC *p = curproc;
  650.  
  651.     for (curproc = proclist; curproc; curproc = curproc->gl_next) {
  652.         FORCE("state %s PC: %lx BP: %lx",
  653.         qname(curproc->wait_q),
  654.         curproc->ctxt[SYSCALL].pc,
  655.         curproc->base);
  656.     }
  657.     curproc = p;        /* restore the real curproc */
  658. #endif
  659. }
  660.